﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using ValidationFramework.Reflection;

namespace ValidationFramework.Tests.Reflection
{
    [TestFixture]
    public class GenericTypeFactoryTest
    {
        #region Test Model

        public interface ITestInterface
        {
            string FirstName { get; set; }
            string LastName { get; set; }
        }
        public interface IUnrelatedInterface
        {
        }
        public class GenericClass<T> : ITestInterface
        {
            // this property will only be set via constructor
            public string Property { get; private set; }

            public GenericClass()
            {
                // ... needs to be public
            }

            /// <summary>
            /// Initializes a new instance of the SimpleGeneric class.
            /// </summary>
            public GenericClass(string property)
            {
                Property = property;
            }

            // --- ITestInterface Members

            public string FirstName
            {
                get;
                set;
            }

            public string LastName
            {
                get;
                set;
            }
        }

        public class FakeGenericFactoryData
        {
            public FakeGenericFactoryData()
            {
                constructorParams = null;
                properties = new Dictionary<string, object>();
            }
            // --- IGenericFactoryData Members

            public object[] constructorParams
            {
                get;
                set;
            }


            public Dictionary<string, object> properties
            {
                get;
                set;
            }

        }

        #endregion

        [TestFixture]
        public class CreateInstance
        {
            [Test]
            public void Should_Build_Correctly_Typed_Generic1()
            {
                // Arrange
                var genericType = typeof(GenericClass<>);
                var typeParam = typeof(int);

                // Act
                var instance = GenericTypeFactory.CreateInstance(genericType, typeParam, null);

                // Assert
                Assert.IsInstanceOfType(typeof(GenericClass<int>), instance);
            }
            [Test]
            public void Should_Build_Correctly_Typed_Generic2()
            {
                // Arrange
                var genericType = typeof(GenericClass<>);
                var typeParam = typeof(DateTime);

                // Act
                var instance = GenericTypeFactory.CreateInstance(genericType, typeParam, null);

                // Assert
                Assert.IsInstanceOfType(typeof(GenericClass<DateTime>), instance);
            }
            [Test]
            public void Should_Use_Correct_Constructor()
            {
                // Arrange
                var genericType = typeof(GenericClass<>);
                var typeParam = typeof(DateTime);
                var ctorParams = new object[] { "Test" };

                // Act
                var instanceDefault = (GenericClass<DateTime>)GenericTypeFactory.CreateInstance(genericType, typeParam, null);
                var instance = (GenericClass<DateTime>)GenericTypeFactory.CreateInstance(genericType, typeParam, ctorParams);

                // Assert
                Assert.AreEqual(null, instanceDefault.Property);
                Assert.AreEqual("Test", instance.Property);
            }

            [Test]
            [ExpectedException(typeof(ArgumentNullException))]
            public void Should_Throw_When_Given_Null_GenericType()
            {
                GenericTypeFactory.CreateInstance(null, typeof(int), new object[0]);

            }

            [Test]
            [ExpectedException(typeof(ArgumentNullException))]
            public void Should_Throw_When_Given_Null_TypeParam()
            {
                GenericTypeFactory.CreateInstance(typeof(GenericClass<>), null, new object[0]);
            }

            //[TestFixture]
            //public class FillInstance
            //{
            //    [Test]
            //    public void Should_Correctly_Fill_Instance_Based_On_Interface()
            //    {
            //        var genericType = typeof(int);

            //        var instance = new GenericClass<int>();
            //        var properties = new Dictionary<string, object>();
            //        properties.Add("FirstName", "Dane");
            //        properties.Add("LastName", "O'Connor");

            //        var filledInstance = GenericTypeFactory.FillInstance<ITestInterface>(instance, properties);

            //        Assert.AreEqual("Dane", filledInstance.FirstName);
            //        Assert.AreEqual("O'Connor", filledInstance.LastName);
            //    }
            //}

        }
    }
}
